package org.jf.tool.fx.jftoolfx.util;

import org.bouncycastle.crypto.digests.*;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;

import java.io.*;

/**
 * @author jifeng_zhang
 * @date 2025/9/30 下午5:22
 */
public class HmacUtil {

    /**
     * 使用 BC 库生成 HMAC
     *
     * @param algorithm 摘要算法
     * @param key       密钥
     * @param data      数据
     * @return
     */
    public static byte[] generateHmac(String algorithm, byte[] key, byte[] data) {
        HMac hmac = createHmac(algorithm);
        KeyParameter keyParam = new KeyParameter(key);

        hmac.init(keyParam);
        hmac.update(data, 0, data.length);

        byte[] result = new byte[hmac.getMacSize()];
        hmac.doFinal(result, 0);
        return result;
    }

    public static byte[] generateHmac(String algorithm, byte[] key, File dataFile) throws IOException {
        HMac hmac = createHmac(algorithm);
        KeyParameter keyParam = new KeyParameter(key);
        hmac.init(keyParam);
        try (InputStream inputStream = new BufferedInputStream(new FileInputStream(dataFile))) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                hmac.update(buffer, 0, bytesRead);
            }
            byte[] result = new byte[hmac.getMacSize()];
            hmac.doFinal(result, 0);
            return result;
        }
    }

    /**
     * 创建 HMac 实例
     */
    private static HMac createHmac(String algorithm) {
        switch (algorithm.toUpperCase()) {
            case "HMAC-MD5":
                return new HMac(new MD5Digest());
            case "HMAC-SHA1":
                return new HMac(new SHA1Digest());
            case "HMAC-SHA224":
                return new HMac(new SHA224Digest());
            case "HMAC-SHA256":
                return new HMac(new SHA256Digest());
            case "HMAC-SHA384":
                return new HMac(new SHA384Digest());
            case "HMAC-SHA512":
                return new HMac(new SHA512Digest());
            case "HMAC-SHA3-224":
                return new HMac(new SHA3Digest(224));
            case "HMAC-SHA3-256":
                return new HMac(new SHA3Digest(256));
            case "HMAC-SHA3-384":
                return new HMac(new SHA3Digest(384));
            case "HMAC-SHA3-512":
                return new HMac(new SHA3Digest(512));
            case "HMAC-RIPEMD128":
                return new HMac(new RIPEMD128Digest());
            case "HMAC-RIPEMD160":
                return new HMac(new RIPEMD160Digest());
            case "HMAC-RIPEMD256":
                return new HMac(new RIPEMD256Digest());
            case "HMAC-RIPEMD320":
                return new HMac(new RIPEMD320Digest());
            default:
                throw new IllegalArgumentException("Unsupported HMAC algorithm: " + algorithm);
        }
    }
}
